
package com.ansion.basedb.storage.secure;

import androidx.annotation.NonNull;

import com.ansion.basetool.preconditions.Preconditions;
import com.ansion.utils.hash.HashUtils;

import java.security.SecureRandom;


public class CipherProtocol {
    public final static int VERSION = 1;
    public final static char PREFIX = 'a' - 1 + VERSION;
    private final static HashCache hashCache = new HashCache();

    @NonNull
    public static String getStorageHashPassword(@NonNull String name) {
        Preconditions.checkNotEmpty(name);
        byte[] output = HashUtils.sha256Bytes(stringToByteArray(name + CipherConfig.KeyValueMeta.META_KEY_MASTER_SALT));
        return HashUtils.sha256(output);
    }

    @NonNull
    public static String getStorageKey(@NonNull String name) {
        Preconditions.checkNotEmpty(name);

        synchronized (hashCache) {
            String hash = hashCache.get(name);
            if (hash != null) {
                return hash;
            }
        }

        byte[] output = HashUtils.sha256Bytes(stringToByteArray(name + CipherConfig.KeyValueMeta.META_KEY_DBKEY_SALT));
        String hash = bytesToHex(PREFIX, output);
        synchronized (hashCache) {
            hashCache.put(name, hash);
        }
        return hash;
    }

    @NonNull
    public static String getRandomStoragePassword() {
        byte[] randomBytes = generateRandomSalt(32);
        return HashUtils.sha256(randomBytes);
    }


    @NonNull
    private static byte[] stringToByteArray(@NonNull String str) {
        Preconditions.checkNotEmpty(str);

        char[] buffer = str.toCharArray();
        int bufLen = buffer.length;
        byte[] b = new byte[bufLen * 2];
        for (int i = 0; i < bufLen; i++) {
            byte tmp = (byte) buffer[i];
            int index = i + i;
            b[index] = tmp;
            b[index + 1] = (byte) (tmp >> 8);
        }
        return b;
    }

    final static char[] hexArray = "0123456789abcdef".toCharArray();

    @NonNull
    public static String bytesToHex(char prefix, @NonNull byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2 + 1];
        hexChars[0] = prefix;

        int v;
        int pos;

        for (int j = 0; j < bytes.length; j++) {
            v = bytes[j] & 0xFF;
            pos = 1 + (j << 1);
            hexChars[pos] = hexArray[v >>> 4];
            hexChars[pos + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    private static final SecureRandom secureRandom = new SecureRandom();

    @NonNull
    public static byte[] generateRandomSalt(int numBytes) {
        byte[] bytes = new byte[numBytes];
        secureRandom.nextBytes(bytes);
        return bytes;
    }


}
